﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.ComponentModel;
using Cwing.UI.Controls;

namespace Cwing.UI.Validation.Manager
{
    public class UserControlValidationManager
    {
        private static readonly Object UserControlValidatingCommand = new object();

        private static readonly Object UserControlValidateCommand = new object();

        private EventHandlerList Events = new EventHandlerList();

        public UserControlValidationManager(UserControl instance)
        {
            UserControl = instance;

            ValidationControls = new List<IValidation>();
            UserControl.Page.PreLoad += new EventHandler(Page_PreLoad);
            UserControl.Page.PreRender += new EventHandler(Page_PreRender);
            UserControl.Page.PreRenderComplete += new EventHandler(Page_PreRenderComplete);
        }

        void Page_PreLoad(object sender, EventArgs e)
        {
            Initial();
        }

        void Page_PreRenderComplete(object sender, EventArgs e)
        {
            ScriptManager.Instance.RendInital(UserControl.Page);
        }

        void Page_PreRender(object sender, EventArgs e)
        {
            ScriptManager.Instance.Rend(UserControl.Page, ValidationControls);
            RenderValidationResult();
        }

        public UserControl UserControl
        {
            get;
            private set;
        }

        private void Initial()
        {
            for (int i = 0; i < UserControl.Controls.Count; i++)
            {
                IValidation v = UserControl.Controls[i] as IValidation;
                if (v != null)
                {
                    if (v.Index == 0)
                    {
                        v.Index = ValidationControls.Count + 1;
                    }
                    if (v.ValidationType != ValidationType.Server && v.ErrorMessageContainer != null)
                    {
                        v.ErrorMessageContainer.Visible = true;
                        v.ErrorMessageContainer.UseForClient = true;
                    }
                    ValidationControls.Add(v);
                }
                if (UserControl.Controls[i].Controls.Count > 0)
                {
                    InitialValidationControl(UserControl.Controls[i].Controls);
                }
            }

            ValidationControls.Sort(delegate(IValidation v1, IValidation v2)
            {
                return v1.Index.CompareTo(v2.Index);
            });
        }

        private void InitialValidationControl(ControlCollection controls)
        {
            if (controls != null && controls.Count > 0)
            {
                for (int i = 0; i < controls.Count; i++)
                {
                    IValidation v = controls[i] as IValidation;
                    if (v != null)
                    {
                        if (v.Index == 0)
                        {
                            v.Index = ValidationControls.Count + 1;
                        }
                        if (v.ValidationType != ValidationType.Server && v.ErrorMessageContainer != null)
                        {
                            v.ErrorMessageContainer.Visible = true;
                            v.ErrorMessageContainer.UseForClient = true;
                        }
                        ValidationControls.Add(v);
                    }
                    if (controls[i].Controls.Count > 0)
                    {
                        InitialValidationControl(controls[i].Controls);
                    }
                }
            }
        }

        private void RenderValidationResult()
        {
            for (int i = 0; i < ValidationControls.Count; i++)
            {
                if (!ValidationControls[i].ValidationResult.IsEmpty && !ValidationControls[i].ValidationResult.Result)
                {
                    if (ValidationControls[i].ErrorMessageContainer != null && ValidationControls[i].IsRendError == false)
                    {
                        ValidationControls[i].IsRendError = true;
                        ValidationControls[i].ErrorMessageContainer.ErrorMessages.Add(ValidationControls[i].ValidationResult.Message);
                        ValidationControls[i].ErrorMessageContainer.Visible = true;
                    }
                }
            }

            for (int i = 0; i < CustomizeValidations.Count; i++)
            {
                if (!CustomizeValidations[i].ValidationResult.IsEmpty && !CustomizeValidations[i].ValidationResult.Result)
                {
                    if (CustomizeValidations[i].ErrorMessageContainer != null && CustomizeValidations[i].IsRendError == false)
                    {
                        CustomizeValidations[i].IsRendError = true;
                        CustomizeValidations[i].ErrorMessageContainer.ErrorMessages.Add(CustomizeValidations[i].ValidationResult.Message);
                        CustomizeValidations[i].ErrorMessageContainer.Visible = true;
                    }
                }
            }
        }

        public List<IValidation> ValidationControls
        {
            get;
            private set;
        }

        /// <summary>
        /// trigger before first control validate begin
        /// </summary>
        public event UserControlValidating UserControlValidating
        {
            add
            {
                Events.AddHandler(UserControlValidatingCommand, value);
            }
            remove
            {
                Events.RemoveHandler(UserControlValidatingCommand, value);
            }
        }

        private void OnUserControlValidating(UserControlValidatingEventArgs args, ValidationResult result)
        {
            UserControlValidating handler = Events[UserControlValidatingCommand] as UserControlValidating;
            if (handler != null)
            {
                handler(args, result);
            }
        }

        /// <summary>
        /// trigger after all control validate finished
        /// </summary>
        public event UserControlValidated UserControlValidated
        {
            add
            {
                Events.AddHandler(UserControlValidateCommand, value);
            }
            remove
            {
                Events.RemoveHandler(UserControlValidateCommand, value);
            }
        }

        private void OnUserControlValidated(UserControlValidatedEventArgs args, ValidationResult result)
        {
            UserControlValidated handler = Events[UserControlValidateCommand] as UserControlValidated;
            if (handler != null)
            {
                handler(args, result);
            }
        }

        public Boolean UserControlValidate()
        {
            return UserControlValidate(String.Empty);
        }

        /// <summary>
        /// execute control validate
        /// </summary>
        /// <returns></returns>
        public Boolean UserControlValidate(String groupName)
        {
            UserControlValidatingEventArgs preValidateArgs = new UserControlValidatingEventArgs();
            preValidateArgs.UserControlInstance = this.UserControl;
            preValidateArgs.Control = firstValidationControl;
            ValidationResult preResult = ValidationResult.Empty;
            OnUserControlValidating(preValidateArgs, preResult);

            if (preValidateArgs.Cancel)
            {
                if (preResult.IsEmpty)
                {
                    return true;
                }
                else
                {
                    CustomizeValidation preCV = new CustomizeValidation(String.Empty, null);
                    preCV.ValidationResult = new ValidationResult();
                    preCV.ValidationResult.Result = preResult.Result;
                    preCV.ValidationResult.Message = preResult.Message;
                    CustomizeValidations.Add(preCV);
                    //deal with Error message if have
                    return preCV.ValidationResult.Result;
                }
            }

            Boolean result = preResult.Result;

            //Start control validateion            
            for (int i = 0; i < ValidationControls.Count; i++)
            {
                //Group Name
                if (!String.IsNullOrEmpty(groupName) && ValidationControls[i].GroupName != groupName)
                    continue;

                ValidationResult _result = ValidationControls[i].Validate();
                if (!_result.IsEmpty)
                {
                    result = result & _result.Result;
                }
            }

            //Customize Validations
            for (int i = 0; i < CustomizeValidations.Count; i++)
            {
                //Group Name
                if (!String.IsNullOrEmpty(groupName) && CustomizeValidations[i].GroupName != groupName)
                    continue;

                ValidationResult _result = CustomizeValidations[i].Validate();
                if (!_result.IsEmpty)
                {
                    result = result & _result.Result;
                }
            }

            CustomizeValidation cValidation = new CustomizeValidation(String.Empty, null);
            cValidation.ValidationResult = new ValidationResult();
            cValidation.ValidationResult.Result = result;
            CustomizeValidations.Add(cValidation);

            //raise PageValidated event
            UserControlValidatedEventArgs afterArgs = new UserControlValidatedEventArgs();
            afterArgs.UserControlInstance = this.UserControl;
            OnUserControlValidated(afterArgs, cValidation.ValidationResult);

            return cValidation.ValidationResult.Result;
        }

        private IValidation firstValidationControl
        {
            get
            {
                return (ValidationControls.Count > 0 ? ValidationControls[0] : null);
            }
        }

        private List<CustomizeValidation> customizeValidations = new List<CustomizeValidation>();

        public List<CustomizeValidation> CustomizeValidations
        {
            get
            {
                return customizeValidations;
            }
        }
    }
}
